import java.awt.*;

public class Car {
    private static final int DECIMALS = 2;

    // previous car to follow
    private Car carToFollow;

    // lead car platoon is following
    private Car leadCar;

    // inputs
    private FuzzyAdapter variables;
        
    // fuzzy elements
    private FuzzySystem fuzzySystem;
    private double pos;
    private double position;
    private double vel;
    private double velocity;
    private double acceleration;
    private double distance;

    // drawing elements
    private int y;
    private int size;
    private Color color;
    private int distanceToPixelScaling = 20; // # pixels per unit distance

    public Car(Car carToFollow, double x, double y, FuzzyAdapter box, Color color) {

        this.carToFollow = carToFollow;
        this.y = (int)y;
        this.variables = box;
        this.color = color;
        reset(x);

        // defaults
        this.size = 20;
        this.leadCar = null;

        this.fuzzySystem = new FuzzySystem();
    }

    public void reset(double x) {
      this.position = x;
      this.velocity = variables.getInitialVelocity();
      this.acceleration = 0.0;
    }

    public void setLeadCar(Car lead) {
      this.leadCar = lead;
    }

    public double getVelocity() {
    	return this.velocity;
    }
    
    public double getAcceleration() {
    	return this.acceleration;
    }
    
    public Color getColor() {
    	return this.color;
    }

    public int getSizeInPixels() {
        return size/distanceToPixelScaling;
    }
    
    private String decimalToString(double d) {
        String s = String.valueOf(d);
        int i = s.indexOf('.');
        if ( i < 0 ) {
            return s;
        }
        else {
            return s.substring( 0, Math.min(i+DECIMALS, s.length()) );
        }
    }

    public void paint(Graphics g) {
        int x = (int)((position - this.leadCar.position) * distanceToPixelScaling) + g.getClipBounds().width - size*4;

        // head lights
        g.setColor(Color.yellow);
        g.fillArc(x, y-(int)(size/4), size*2, size, -20, 45);
        g.fillArc(x, y+(int)(size/4), size*2, size, -25, 45);

        // tail lights
        g.setColor(Color.red);
        g.fillOval(x-(int)(size/4), y+(int)(size/5), size/5, size/5);
        g.fillOval(x-(int)(size/4), y+(int)(size*3/5), size/5, size/5);

        // car body
        g.setColor(color);
        g.fillRect(x, y, size, size);
        g.drawString( "" + decimalToString(velocity) +" m/s", x, y - (int)(size*0.1) );
        g.drawString( "" + decimalToString(acceleration) +" m/s^2", x, y + (int)(size*1.6) );
        if ( this.leadCar != this ) {
            g.setColor(Color.white);
            g.drawString( "" + decimalToString(distance) +" m", x + (int)(distance/2*distanceToPixelScaling), y - size );
        }
    }

    public void pre_iteration() {
      this.pos = this.position;
      this.vel = this.velocity;
    }

    public void post_iteration() {
      this.position = this.pos; 
      this.velocity = this.vel;
    }

    /**
     * Move the car forward for the given amount of time.
     * @param dt The change in time to update for.
     */
    public void update(double dt, double num_iter) {
        assert this.leadCar != null : "must have a lead car";

        for (double i = 0; i < num_iter; i++) {
          if (carToFollow != null) {
              // we are following, so figure out the distance from them
              double backOfPrevious = carToFollow.position - size/distanceToPixelScaling;
              double frontOfThis = this.position + size/distanceToPixelScaling;

              distance = backOfPrevious - frontOfThis;
          }
          else {
              // we are lead car, set distance to be perfect
              distance = variables.getDesiredDistance();
          }
          acceleration = fuzzySystem.computeAcceleration(vel, distance);

          // modify position (will be relative to lead car)
          vel = Math.max(0, velocity + dt * acceleration);
          pos = position + dt * vel;
        }
    }
}
